/*
 * File database TAD.
 * $Rev: 163 $
 */

#ifndef __FILE_DB_H
#define __FILE_DB_H

#include <stdbool.h>
#include <sys/types.h>

#define FRAGMENT_SIZE 1024 /* Bytes */

typedef struct _file file; /* a file */
typedef unsigned int fragment_pos_t; /* a file fragment position */

/* MD5 hexa representation terminated by '\0' */
typedef char *md5_t;

/********************************** File TAD **********************************/

/* Queries */

/*
 * PRE: `a_file' != NULL
 * POST: returns whether `a_file' is partial or not
 */
bool file_is_partial(file *a_file);

/*
 * PRE: `a_file' != NULL
 * POST: returns whether `a_file' has the fragment info retrieved from the index
 */
bool file_has_index_info(file *a_file);

/*
 * PRE: `a_file' != NULL
 * POST: returns the amount of fragments in `a_file'
 */
fragment_pos_t file_fragment_count(file *a_file);

/*
 * PRE: `a_file' != NULL
 * POST: returns whether `a_position' is a valid fragment position in `a_file'
 */
bool file_valid_fragment_position(file *a_file, fragment_pos_t a_position);

/* Access */

/*
 * PRE: `a_file' != NULL
 * POST: returns the size in bytes of `a_file'
 */
off_t file_size(file *a_file);

/*
 * PRE: `a_file' != NULL
 * POST: returns the name of `a_file'
 * NOTE: the returned string MUST NOT BE FREED NOR MODIFIED
 */
char *file_name(file *a_file);

/*
 * PRE: `a_file' != NULL
 * POST: returns the MD5 of `a_file'
 * NOTE: the returned MD5 MUST NOT BE FREED NOR MODIFIED
 */
md5_t file_md5(file *a_file);

/*
 * PRE: `a_file' != NULL and `has_index_info(a_file)'
 * POST: returns the fragment info of `a_file'
 * NOTE: the returned list MUST NOT BE FREED NOR MODIFIED
 */
md5_t *file_index_info(file *a_file);

/*
 * PRE: `a_file' != NULL and `file_valid_fragment_position(a_file, a_position)'
 *      `fragment' points to an area of at least FRAGMENT_SIZE bytes.
 * POST: the data for the slice of `a_file' at position `a_position' is stored
 *       at `fragment'. returns the size of the slice actually read, or -1
 *       on error.
 * NOTE: the returned chunk of data MUST BE FREED
 *       by the calling process. Otherwise mem leaks are ensured.
 */
size_t file_slice(file *a_file, fragment_pos_t a_position, char *fragment);

/*
 * PRE: `a_file' != NULL and `res_len' != NULL
 * POST: returns NULL on error, otherwise
 *       a list with the MD5 of all the fragments from `a_file' IN DISK
 *       (the list will have `*res_len' members)
 * NOTE: the returned list MUST BE RECURSIVELY FREED
 *       by the calling process. Otherwise mem leaks are ensured.
 */
md5_t *file_fragments_in_disk(file *a_file, unsigned int *res_len);

/* Operations */

/*
 * PRE: `a_file' != NULL and `file_valid_fragment_position(a_file, a_position)' and
 *      `data' != NULL and `data_len <= FRAGMENT_SIZE)'
 * POST: writes fragment at `data' at position `a_position' to disk using `a_file'
 *       `a_position' counts from 0.
 */
void file_put_slice(file *a_file, fragment_pos_t a_position, char *data, unsigned int data_len);

/*
 * PRE: `a_file' != NULL and `info != NULL' and `info_len <= file_fragment_count(a_file)'
 * POST: returns NULL on error, otherwise
 *       sets `info' into `a_file' as fragment info from index
 */
file *file_set_index_info(file *a_file, md5_t *info, unsigned int info_len);

/***************************** File Database TAD *****************************/

typedef struct _file_db file_db; /* a file database */

/*
 * PRE: `a_path' is a valid path name, and is a directory
 * POST: returns NULL on error, otherwise
 *       a newly allocated file database pointing to `a_path'
 */
file_db *file_db_create(const char *a_path);

/*
 * PRE: `a_db' != NULL and was created with `file_db_create'
 * POST: frees the resources used by `a_db'
 */
void file_db_destroy(file_db *a_db);

/* Access */

/*
 * PRE: `a_db' != NULL and `a_file_md5' != NULL
 * POST: returns NULL on error, otherwise
 *       the file instance identified by `a_file_md5'
 * NOTE: the returned file MUST NOT BE FREED
 */
file *file_db_get_file(file_db *a_db, md5_t a_file_md5);

/*
 * PRE: `a_db' != NULL and `res_len' != NULL 
 * POST: returns NULL on error, otherwise
 *       a list with the MD5 of all complete files inside `a_db'
 *       (the list will have `*res_len' members)
 * NOTE: the returned list MUST BE RECURSIVELY FREED
 *       by the calling process. Otherwise mem leaks are ensured.
 */
md5_t *file_db_get_complete_files(file_db *a_db, unsigned int *res_len);

/* Operations */

/*
 * PRE: `a_db' != NULL and `a_file_md5' != NULL and
 *      `a_file_name' != NULL  and `a_file_size' >= 0 
 * POST: returns NULL on error, otherwise
 *       the file instance identified by `a_file_md5',
 *       whose name is `a_file_name' and size `a_file_size'
 * NOTE: the returned file MUST NOT BE FREED
 */
file *file_db_create_file(file_db *a_db, md5_t a_file_md5,
                  char *a_file_name, size_t a_file_size);

/*
 * PRE: `a_db' != NULL and `a_file_md5' != NULL
 * POST: moves file indentified by `a_file_md5' from partials
 *       directory to completes directory.
 *       Returns true on success. This feature also checks that
 *       `file_md5(file_db_get_file(a_db, a_file_md5))' is equals
 *       to actual MD5 of file content.
 */
bool file_db_mark_as_complete(file_db *a_db, md5_t a_file_md5);

#endif /* __FILE_DB_H */
